package yscmd

import (
	"context"
	"fmt"
	"gitee.com/kmyss/gf-ex/ysbuild"
	"gitee.com/kmyss/gf-ex/yslog"
	"github.com/gogf/gf/v2/container/gmap"
	"github.com/gogf/gf/v2/frame/g"
	"github.com/gogf/gf/v2/util/gconv"
)

type Command struct {
	Use     string // 命令名称
	Short   string // 命令短描述
	Long    string // 命令长描述
	Example string // 命令使用案例
	Note    string // 命令的详细说明
	
	Run  func(*Command)
	Help func(*Command)
	
	ctx context.Context // 链式记录使用
	
	parent   *Command      // 父命令
	commands *gmap.ListMap // 子命令
	flags    *gmap.ListMap // 标签
	
	maxCommandLen int // 辅助记录命令长度
	maxFlagLen    int // 辅助记录flag的最大值
}

func (c *Command) SetContext(ctx context.Context) {
	c.ctx = ctx
}

func (c *Command) Context() context.Context {
	return c.ctx
}

func (c *Command) ShowHelp() {
	if !g.IsEmpty(c.Help) {
		c.Help(c)
	} else {
		yslog.Warningf("%s 命令没有帮助信息", c.Use)
	}
}

func (c *Command) PrintHelp() {
	yslog.Print(c.GetHelp())
}

// GetHelp 使用模板创建默认的帮助命令
func (c *Command) GetHelp() string {
	out := ""
	out += c.descriptionInfo()
	out += c.useInfo()
	out += c.commandsInfo()
	out += c.flagsInfo()
	out += c.exampleInfo()
	out += c.noteInfo()
	
	return out
}

func (c *Command) descriptionInfo() string {
	if g.IsEmpty(c.Long) {
		return ""
	} else {
		return fmt.Sprintf(`
介绍：%s`, c.Long)
	}
}

func (c *Command) useInfo() string {
	appName := c.Use
	if g.IsEmpty(c.Use) && g.IsEmpty(c.parent) {
		appName = ysbuild.APPName
	}
	
	parents := c.findParents()
	
	cmd := ""
	if !g.IsEmpty(parents) {
		cmd += parents + " "
	}
	cmd += appName
	
	return fmt.Sprintf(`
使用：
    %s [命令] [选项]
`, cmd)
}

func (c *Command) findParents() string {
	out := ""
	if !g.IsEmpty(c.parent) {
		_tmp := c.parent.findParents()
		if len(_tmp) > 0 {
			out += _tmp + " "
		}
		out += c.parent.Use
	}
	return out
}

func (c *Command) commandsInfo() string {
	if c.commands.IsEmpty() {
		return ""
	} else {
		out := "\n命令:"
		for _, v := range c.commands.Values() {
			command := v.(*Command)
			out += "\n" + command.getCommandInfo(c.maxCommandLen)
		}
		return out + "\n"
	}
}

func (c *Command) getCommandInfo(commandLen int) string {
	fmtStr := `    %-` + gconv.String(commandLen) + `s   %s`
	return fmt.Sprintf(fmtStr, c.Use, c.Short)
}

func (c *Command) flagsInfo() string {
	if c.flags.IsEmpty() {
		return ""
	} else {
		out := "\n选项:"
		for _, v := range c.flags.Values() {
			flag := v.(*Flag)
			out += "\n" + flag.getFlagInfo() + "\n"
		}
		return out
	}
}

func (c *Command) exampleInfo() string {
	if g.IsEmpty(c.Example) {
		return ""
	} else {
		return fmt.Sprintf(`
样例：%s`, c.Example)
	}
}

func (c *Command) noteInfo() string {
	if g.IsEmpty(c.Note) {
		return ""
	} else {
		return fmt.Sprintf(`
说明：%s`, c.Note)
	}
}

// Exec 执行命令的 Run 函数
func (c *Command) Exec(ctx context.Context) {
	c.ctx = ctx
	
	if g.IsEmpty(c.Run) {
		yslog.Fatal("没有可执行的函数!")
	} else {
		c.Run(c)
	}
}

// RunChildCmd 运行子命令，<cmdUse> 表示字命令的字符.
// 当 <cmdUse> 为空时, 判断命令是否可以执行shell 可以则执行
// 当 <cmdUse> 不存在时, 显示当前命令的帮助信息
// <cmdUse> 直接执行
func (c *Command) RunChildCmd(cmdUse string) {
	// 命令为空
	if g.IsEmpty(cmdUse) {
		if c.commands.Contains(CmdShellUse) {
			yslog.Warning("未输入后续命令自动进入 shell 模式")
			c.commands.Get(CmdShellUse).(*Command).Exec(c.ctx)
		} else {
			yslog.Error("请输入后续命令")
			c.ShowHelp()
		}
		return
	}
	// 命令不存在
	if !c.commands.Contains(cmdUse) {
		yslog.Error("没有命令: ", cmdUse)
		c.ShowHelp()
		return
	}
	
	get := c.commands.Get(cmdUse)
	get.(*Command).Exec(c.ctx)
}

func (c *Command) AddCommand(cmd *Command) bool {
	if len(cmd.Use) > c.maxCommandLen {
		c.maxCommandLen = len(cmd.Use)
	}
	cmd.parent = c
	return c.commands.SetIfNotExist(cmd.Use, cmd)
}

func (c *Command) AddFlag(f *Flag) bool {
	
	key := ""
	if !g.IsEmpty(f.ConfigKey()) {
		key = f.ConfigKey()
	} else if !g.IsEmpty(f.LongKey()) {
		key = f.LongKey()
	} else if !g.IsEmpty(f.ShortKey()) {
		key = f.ShortKey()
	} else {
		return false
	}
	
	return c.flags.SetIfNotExist(key, f)
}

func (c *Command) Parent() *Command {
	return c.parent
}

func (c *Command) Child(use string) *Command {
	return c.commands.Get(use).(*Command)
}
